// 文件名：serialization_buffer.cpp
// 目的：演示如何将一个二进制头部（Header）与文本负载（payload）拼接成字节序列（packet），
//      并以十六进制格式打印出来。
// 说明：该示例直接按本机内存布局与本机字节序（endianness）将 Header 序列化到缓冲区。
//      在跨平台/跨进程/网络传输场景下，应明确字节序与结构体对齐/填充策略，
//      否则在不同平台之间解析可能失败。

#include <cstdint>   // std::uint32_t, std::uint16_t, std::uint8_t
#include <vector>    // std::vector
#include <string>    // std::string
#include <iostream>  // std::cout
#include <iomanip>   // std::hex, std::setw, std::setfill, std::dec

// 数据包的头部结构
// 注意：该结构的布局（字段顺序与对齐）依赖编译器与 ABI，通常为紧凑的 8 字节：
//       4 字节 magic + 2 字节 version + 2 字节 payloadSize。
//       但严格来说，C++ 标准允许插入填充字节（padding），因此在跨编译器/平台时
//       推荐使用静态断言或显式打包（如 #pragma pack 或 [[gnu::packed]] 等，需谨慎）。
//       另外，所有字段当前均为主机字节序。如需网络字节序请显式转换（htonl/htons 或自实现）。
struct Header {
    std::uint32_t magic;       // 魔数：用于快速校验与同步（示例：0xABCD1234）
    std::uint16_t version;     // 协议版本号
    std::uint16_t payloadSize; // 负载区（payload）的字节数（应与实际负载长度一致）
};

// 将 Header 与 payload 按内存布局拼接为连续的字节缓冲区
// 参数：
//   header  - 包头（按当前平台字节序与布局拷贝原始字节）
//   payload - 负载（示例中为 ASCII 文本 "Hello"）
// 返回：包含 [Header原始字节 | payload字节] 的向量
// 警告：
//   1) 字节序：header 各字段为本机字节序；跨网络/平台应转换为约定字节序（如大端）。
//   2) 布局/填充：如 Header 存在填充字节，则也会被一并拷贝；解析端需完全一致的布局。
//   3) 严格别名/类型别名：按标准，使用 unsigned char/char/std::byte 读取对象表示是允许的；
//      std::uint8_t 通常是 unsigned char 的别名，实际实现通常安全，但标准并未强制。
//      若需最严谨，可改用 reinterpret_cast<const unsigned char*> 或 std::bit_cast（C++20）。
std::vector<std::uint8_t> buildPacket(const Header& header, const std::string& payload) {
    std::vector<std::uint8_t> buffer;

    // 预留足够的容量，避免中途多次扩容（提升性能）
    buffer.reserve(sizeof(Header) + payload.size());

    // 将 Header 视为一段连续的字节并插入到缓冲区尾部
    // 注意：这里直接复制了结构体的内存表示（包含可能的填充与本机字节序）
    const auto* headerBytes = reinterpret_cast<const std::uint8_t*>(&header);
    buffer.insert(buffer.end(), headerBytes, headerBytes + sizeof(Header));

    // 将 payload 的字节直接追加到缓冲区
    // std::string 的迭代器提供 char 字节；这里会逐字节拷贝
    buffer.insert(buffer.end(), payload.begin(), payload.end());

    return buffer;
}

// 以十六进制形式转储缓冲区内容，便于调试与验证
// 格式：每字节以 "0x.." 形式输出，每 8 个字节换一行
void dumpBuffer(const std::vector<std::uint8_t>& buffer) {
    for (std::size_t i = 0; i < buffer.size(); ++i) {
        if (i && i % 8 == 0) std::cout << '\n';
        // 使用 std::hex 切换到十六进制，std::setw(2) 固定宽度为 2，
        // std::setfill('0') 以 0 填充不足位，static_cast<int> 避免以字符打印
        std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0')
                  << static_cast<int>(buffer[i]) << ' ';
    }
    // 切回十进制，以免影响后续输出
    std::cout << std::dec << "\n";
}

int main() {
    // 构造一个示例 Header 与 payload
    // 注意：payloadSize 应与 payload.size() 保持一致，实际工程中建议自动填充或断言校验
    Header header{0xABCD1234u, 1u, 5u};
    std::string payload = "Hello";

    // 构建数据包：按 [Header原始字节 | payload字节] 拼接
    auto packet = buildPacket(header, payload);

    // 打印整体大小（单位：字节）
    std::cout << "Packet size: " << packet.size() << " bytes\n";

    // 十六进制转储字节内容
    dumpBuffer(packet);

    // 额外建议（非示例代码的一部分）：
    // - 可添加静态断言，确保 Header 尺寸符合预期：
    //   static_assert(sizeof(Header) == 8, "Header size unexpected. Check packing/alignment.");
    // - 跨平台/网络：将字段转换为网络字节序后再写入缓冲，以消除端序差异。
    // - 更安全的序列化：逐字段写入（手动字节序）或使用规范化序列化格式（如 TLV/CBOR/Protobuf）。
    return 0;
}